《c语言深度剖析》笔记1

您所在的位置:网站首页 c语言深度剖析 cpu 《c语言深度剖析》笔记1

《c语言深度剖析》笔记1

2024-01-19 09:55| 来源: 网络整理| 查看: 265

1.

break 跳出当前循环 ,continue 结束当前循环,开始下一轮循环

break 关键字很重要,表示终止本层循环。现在这个例子只有一层循环,当代码执行到 break 时,循环便终止。 如果把break 换成continue 会是什么样子呢?continue 表示终止本次(本轮)循环。当 代码执行到continue 时,本轮循环终止,进入下一轮循环。 while(1)也有写成while(true) 或者while(1==1) 或者while((bool) 1)等形式的,效果一 样。 do-while 循环:先执行do 后面的代码,然后再判断while 后面括号里的值,如果为真, 循环开始;否则,循环不开始。其用法与while 循环没有区别,但相对较少用。

for 循环:for 循环可以很容易的控制循环次数,多用于事先知道循环次数的情况下。 留一个问题:在switch case 语句中能否使用continue 关键字?为什么?

不能 continue 只能用在循环结构里 除非switch case 里有循环

2.

定义:所谓的定义就是(编译器)创建一个对象,为这个对象分配一块内存并给它取上一个名字,这个名字就是我们经常所说的变量名或对象名

什么是声明:有两重含义,如下: 第一重含义:告诉编译器,这个名字已经匹配到一块内存上了,比如extern

第二重含义:告诉编译器,我这个名字我先预定了,别的地方再也不能用它来作为变量名或对象名

定义声明最重要的区别:定义创建了对象并为这个对象分配了内存,声明没有分配内存

举个例子: A)int i;(定义) B)extern int i;(声明)(关于extern,后面解释)

3.

static面向过程的用法:

第一个作用:修饰变量。变量又分为局部和全局变量,但它们都存在内存的静态区。 静态全局变量,作用域仅限于变量被定义的文件中,其他文件即使用extern 声明也没法使用他 由于被static 修饰的变量总是存在内存的静态区,所以即使这个函数运行结束,这个静态变量的值还是不会被销毁,函数下次使用时仍然能用到这个值。

第二个作用:修饰函数。函数前加static 使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)

还有static面向对象的用法?

4.

在32 位的系统上

short 咔出来的内存大小是2 个byte;

int 咔出来的内存大小是4 个byte;

long 咔出来的内存大小是4 个byte;

float 咔出来的内存大小是4 个byte; double 咔出来的内存大小是8 个byte;

char 咔出来的内存大小是1 个byte。

(注意这里指一般情况,可能不同的平台还会有所不同,具体平台可以用sizeof 关键字测试一下)

5.

sizeof 是关键字不是函数,其实就算不知道它是否为32 个关键字之一时,我们也可以 借助编译器确定它的身份。看下面的例子: int i=0; A),sizeof(int); B),sizeof(i); C),sizeof int; D),sizeof i; 毫无疑问,32 位系统下A),B)的值为4。那C)的呢?D)的呢? 在32 位系统下,通过Visual C++6.0 或任意一编译器调试,我们发现D)的结果也为4。 咦?sizeof 后面的括号呢?没有括号居然也行,那想想,函数名后面没有括号行吗?由此轻 易得出sizeof 绝非函数。 好,再看C)。编译器怎么怎么提示出错呢?不是说sizeof 是个关键字,其后面的括号 可以没有么?那你想想sizeof int 表示什么啊?int 前面加一个关键字?类型扩展?明显不 正确,我们可以在int 前加unsigned,const 等关键字但不能加sizeof。好,记住:sizeof 在 计算变量所占空间大小时,括号可以省略,而计算类型(模子)大小时不能省略。一般情况下, 咱也别偷这个懒,乖乖的写上括号,继续装作一个“函数”,做一个“披着函数皮的关键字”。 做我的关键字,让人家认为是函数去吧。

int *p = NULL; sizeof(p)的值是多少?=4 sizeof(*p)呢?=4

char* p = NULL;

sizeof(p) = 4;

sizeof(*p) = 1;

int a[100]; sizeof (a) 的值是多少?=400 sizeof(a[100])呢?//请尤其注意本例。=4 sizeof(&a)呢?=4 sizeof(&a[0])呢?=4

int b[100]; void fun(int b[100])//数组作为参数传递传递的是指针,sizeof是指针长度。当把一个数组定义为函数参数时,可以选择把它定义为数组,也可以定义为指针,不管用哪种方法在函数内部获得的都是指针 {

sizeof(b);// sizeof (b) 的值是多少?=4

}

void fun(int (&b)[100])//c++传递按引用传递的话那么sizeof就是数组长度

{

sizeof(b);// sizeof (b) 的值是多少?=400

}

6.

把基本数据类型的最高位腾出来,用来存符号,同时约定如下:最高位如果是1,表明这个数是负数,其值为除最高位以外的剩余位的值添上这个“-”号;如果最高位是0,表明这个数是正数,其值为除最高位以外的剩余位的值。 这样的话,一个32位的signed int类型整数其值表示法范围为:- 231~231 -1;8 位的 char类型数其值表示的范围为- 27~27 -1。一个32位的unsigned int类型整数其值表示法 范围为:0~ 232 -1;8位的char类型数其值表示的范围为0~28 -1。同样我们的signed 关 键字也很宽恒大量,你也可以完全当它不存在,编译器缺省默认情况下数据为signed 类型 的。

上面的解释很容易理解,下面就考虑一下这个问题: int main() {

char a[1000];

int i;

for(i=0; i printf("%u\n",i); }

因为你定义的i是无符号整型(unsigned int),当i为0时,再减1,就变成了65535,永远不会小于0,所以循环的条件永远成立,是个死循环,改正方法是将unsigned i;改为int i; 还有就是如果你想只输出9到1,而不输出0的话,还可以将for(i=9;i>=0;i--)改为for(i=9;i>0;i--)

7.

bool 变量与“零值”进行比较,采用

if(bTestFlag); if(!bTestFlag);

大家都知道if 语句是靠其后面的括号里的表达式的值来进行分支跳转的。表达式如果 为真,则执行if 语句后面紧跟的代码;否则不执行。那显然,本组的写法很好,既不会引 起误会,也不会由于TRUE 或FLASE 的不同定义值而出错。记住:以后写代码就得这样写。

float 变量与“零值”进行比较

if((fTestVal >= -EPSINON) && (fTestVal }stu; sizeof(stu)的值是多少呢

不是0,而是1

假设结构体内只有一个char 型的数据 成员,那其大小为1byte(这里先不考虑内存对齐的情况).也就是说非空结构体类型数据最 少需要占一个字节的空间,而空结构体类型数据总不能比最小的非空结构体类型数据所占 的空间大吧

而最小的数据成员需要1 个byte,编译器为每个结构体类型数据至少预留1 个byte 的空间。所以,空结构体的大小就定位1 个byte。

结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员(了解),但结 构中的柔性数组成员前面必须至少一个其他成员。柔性数组成员允许结构中包含一个大小可 变的数组。。sizeof 返回的这种结构大小不包括柔性数组的内存。包含柔性数组成员的结构用 malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组 的预期大小。

typedef struct st_type {

int i;

int a[];

}type_a; 这样我们就可以定义一个可变长的结构体, 用sizeof(type_a) 得到的只有4 , 就是 sizeof(i)=sizeof(int)。那个0 个元素的数组没有占用空间,而后我们可以进行变长操作了。通 过如下表达式给结构体分配内存: type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));

在C++里struct 关键字与class 关键字一般可以通用,只有一个很小的区别。struct 的成 员默认情况下属性是public 的,而class 成员却是private 的。很多人觉得不好记,其实很容 易。你平时用结构体时用public 修饰它的成员了吗?既然struct 关键字与class 关键字可以 通用,你也不要认为结构体内不能放函数了

15

union 维护足够的空间来置放多个数据成员中的“一种”,而不是为每一个数据成员配置 空间,在union 中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所 有的数据成员具有相同的起始地址。例子如下: union StateMachine {

char character;

int number;

char *str;

double exp;

}; 一个union 只配置一个足够大的空间以来容纳最大长度的数据成员,以上例而言,最大 长度是double 型态,所以StateMachine 的空间大小就是double 数据类型的大小。

下面再看一个例子: union {

int i;

char a[2];

}*p, u; p =&u; p->a[0] = 0x39; p->a[1] = 0x38; p.i 的值应该为多少呢?

这里需要考虑存储模式:大端模式和小端模式。 大端模式(Big_endian):字数据的高字节存储在低地址中,而字数据的低字节则存放 在高地址中。 小端模式(Little_endian):字数据的高字节存储在高地址中,而字数据的低字节则存放 在低地址中。 union 型数据所占的空间等于其最大的成员所占的空间。对union 型的成员的存取都是 相对于该联合体基地址的偏移量为0 处开始,也就是联合体的访问不论对哪个变量的存取都 是从union 的首地址位置开始。如此一解释,上面的问题是否已经有了答案呢?

上述问题似乎还比较简单,那来个有技术含量的:请写一个C 函数,若处理器是 Big_endian 的,则返回0;若是Little_endian 的,则返回1。 先分析一下,按照上面关于大小端模式的定义,假设int 类型变量i 被初始化为1。 以大端模式存储,其内存布局如下图:

以小端模式存储,其内存布局如下图:

变量i 占4 个字节,但只有一个字节的值为1,另外三个字节的值都为0。如果取出低 地址上的值为0,毫无疑问,这是大端模式;如果取出低地址上的值为1,毫无疑问,这是 小端模式。既然如此,我们完全可以利用union 类型数据的特点:所有成员的起始地址一致。 到现在,应该知道怎么写了吧?参考答案如下: int checkSystem( ) {

union check

{

int i;

char ch;

} c;

c.i = 1;

return (c.ch ==1);

} 现在你可以用这个函数来测试你当前系统的存储模式了

16

typedef 的真正意思是给一个已经存在的数据类型(注意:是类型不是变量)取一个别 名,而非定义一个新的数据类型

在实际项目中,为了方便,可能很多数据类型(尤其是结构体之类的自定义数据类型) 需要我们重新取一个适用实际情况的别名。这时候typedef 就可以帮助我们。例如: typedef struct student { //code }Stu_st,*Stu_pst;//命名规则请参考本章前面部分 A),struct student stu1;和Stu_st stu1;没有区别。 B),struct student *stu2;和Stu_pst stu2;和Stu_st *stu2;没有区别。

好,下面再把typedef 与const 放在一起看看: C),const Stu_pst stu3; D),Stu_pst const stu4; 大多数初学者认为C)里const 修饰的是stu3 指向的对象;D)里const 修饰的是stu4 这个指针。很遗憾,C)里const 修饰的并不是stu3 指向的对象。那const 这时候到底修饰 的是什么呢?我们在讲解const int i 的时候说过const 放在类型名“int”前后都行;而const int *p 与int * const p 则完全不一样。也就是说,我们看const 修饰谁都时候完全可以将数据类 型名视而不见,当它不存在。反过来再看“const Stu_pst stu3”,Stu_pst 是“struct student { /*code*/} *”的别名, “struct student {/*code*/} *”是一个整体。对于编译器来说,只认为 Stu_pst 是一个类型名,所以在解析的时候很自然的把“Stu_pst”这个数据类型名忽略掉。 现在知道const 到底修饰的是什么了吧?^_^。???



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3